﻿/**
* ...
* @author Default
* @version 0.1
*/

package kizzo.utils 
{
	import away3d.core.material.ColorMaterial;
	import away3d.core.material.WireColorMaterial;
	import flash.events.EventDispatcher;
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.display.BitmapData;
	import flash.utils.setInterval;
	import flash.utils.clearInterval;
	
	import away3d.core.scene.Object3D;
	import away3d.core.scene.ObjectContainer3D;
	import away3d.loaders.Collada;
	import away3d.core.sprite.MovieClipSprite;
	import away3d.core.material.BitmapMaterial;
	import away3d.core.material.WhiteShadingBitmapMaterial;
	import away3d.core.mesh.Mesh;

	import kizzo.utils.*;

	public class ModelLibrary3D extends EventDispatcher
	{
		var obj_lib:Array;
		var mat_lib:Array;
		var tex_lib:Library;
		var int_array:Array;
		
		var objects_to_create:Number;
		
		public var xml_data:XML;
		var xml_loader:URLLoader;
		
		public static const OBJECT_CREATED:String = "objectCreated";
		public static const ALL_CREATED:String = "allCreated";
		
		function ModelLibrary3D()
		{
			this.obj_lib = [];			
			this.mat_lib = [];
			this.tex_lib = new Library();
			this.int_array = [];
			
			this.objects_to_create = 0;
		}
		
		public function load_xml_data(xml_url:String):void
		{
			this.xml_loader = new URLLoader(new URLRequest(xml_url));
			this.xml_loader.addEventListener(Event.COMPLETE, process_xml_data);
		}
		
		function process_xml_data(event:Event)
		{
			this.xml_data = XML (this.xml_loader.data);				
			for (var i:uint = 0; this.xml_data.assets.object3d[i] != null; i++)
			{				
				create_object(this.xml_data.assets.object3d[i]);
			}
		}
		
		public function create_object(object_node:XML):void  // object that requires the loading of external assets
		{				
			var name:String = object_node.@name;
			var type:String = object_node.@type;
			
			this.objects_to_create++;
			
			var mat_type:String;
			var model_url:String;
			var tex_url:String;			
			var command_queue:CommandQueue;	
			
			switch (type)
			{
				case "Collada":
				{
					command_queue = new CommandQueue();					
					
					mat_type = object_node.material;
					model_url = object_node.model;
					tex_url = object_node.texture;
					
					var load_texture:Command = new Command(this.tex_lib.load, [tex_url, name], Command.ASYNC, this.tex_lib, this.tex_lib, new CustomEvent(Library.LOAD_ITEM, {name:name}));
					var create_material:Command = new Command(this.create_material, [mat_type, name], Command.SYNC, this);
					var load_model:Command = new Command(this.load_model, [model_url, name], Command.ASYNC, this, this.tex_lib, new CustomEvent(OBJECT_CREATED, {name:name}));
					
					command_queue.add(load_texture);
					command_queue.add(create_material);
					command_queue.add(load_model);
					
					command_queue.execute();
					
					break;
				}				
				
				case "Container":
				{
					this.obj_lib[name] = new ObjectContainer3D();
					this.objects_to_create--;
					break;
				}
				
				case "MovieClipSprite":
				{						
					command_queue = new CommandQueue();
					
					tex_url = object_node.texture;
					
					var load_sprite_texture:Command = new Command(this.tex_lib.load, [tex_url, name], Command.ASYNC, this.tex_lib, this.tex_lib, new CustomEvent(Library.LOAD_ITEM, {name:name}));
					var create_sprite:Command  = new Command(this.create_sprite, [name], Command.SYNC, this);
					
					command_queue.add(load_sprite_texture);
					command_queue.add(create_sprite);
					
					command_queue.execute();
					
					break;
				}
			}		
			
		}
		
		function process_xml_derived()   
		{
			for (var i:uint = 0; this.xml_data.derived_assets.object3d[i] != null; i++)
			{				
				create_derived_object(this.xml_data.derived_assets.object3d[i]);
			}
		}
		
		function create_derived_object(object_node:XML):void // object that uses already loaded assets
		{
			var name:String = object_node.@name;			
			var type:String = object_node.@type;
			
			//this.objects_to_create++;
			
			var mat_type:String;
			
			switch (type)
			{
				case "Object3D - Tex Mod":
				{
					var clone_name:String = object_node.texture.name;
					this.obj_lib[name] = this.obj_lib[clone_name].clone();
					this.obj_lib[name].name = name;
					
					for each (var child:Object3D in (this.obj_lib[clone_name] as ObjectContainer3D).children)
					{
						var mesh:Mesh = (child as Mesh);
						mesh.bothsides = true;
						trace(mesh.material);
						mesh.material = new BitmapMaterial(this.tex_lib.getBitmapData("rotator_1"));
					}
					
					break;
				}
			}
		}
				
		function wait_tex_load()
		{
			
		}
				
		function create_material(mat_type:String, name:String)
		{
			switch (mat_type)
			{
				case "WhiteShadingBitmapMaterial":
				{
					this.mat_lib[name] = new WhiteShadingBitmapMaterial(this.tex_lib.getBitmapData(name), {smooth:false});
					break;
				}
				case "BitmapMaterial":
				{
					this.mat_lib[name] = new BitmapMaterial(this.tex_lib.getBitmapData(name));
					break;
				}				
			}			
		}
		
		function load_model(model_url:String, name:String)
		{
			this.obj_lib[name] = Collada.load(model_url, {material:this.mat_lib[name], name:name});			
			this.int_array[name] = setInterval(check_load, 100, name);
		}		
		
		function check_load(name:String)
		{					
			if (this.obj_lib[name].result != null)
			{				
				clearInterval (this.int_array[name]);
				this.obj_lib[name] = this.obj_lib[name].result;
				dispatchEvent(new CustomEvent(OBJECT_CREATED, {name:name}));
				
				this.objects_to_create--;
				if (this.objects_to_create == 0)
				{
					process_xml_derived();
					dispatchEvent(new CustomEvent(ALL_CREATED, {}));
				}
			}			
		}
		
		function create_sprite(name:String)
		{	
			this.obj_lib[name] = new MovieClipSprite(this.tex_lib.getBitmap(name), null);
			this.objects_to_create--;
			if (this.objects_to_create == 0)
				dispatchEvent(new CustomEvent(ALL_CREATED, {}));			
		}
		
		public function get(name:String):Object3D
		{
			if (this.obj_lib[name] != null)
				return this.obj_lib[name];
			else 
				return null;
		}
		
		public function getClone(name:String):Object3D
		{
			if (this.obj_lib[name] != null)
				return this.obj_lib[name].clone();
			else 
				return null;
		}		
		
		public function getBitmapData(name:String):BitmapData
		{
			return this.tex_lib.getBitmapData(name);
		}		
		
		public function add(obj3D:Object3D, name:String)
		{
			if (this.obj_lib[name] != null)
				throw new Error ("Duplicate model library entry with name : " + name + "\nRename the object or delete the old one first");
			else
				this.obj_lib[name] = obj3D;
		}
		
	}
	
}